package com.lms.common.web.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lms.common.pure.entity.IBaseEntity;
import com.lms.common.pure.query.QueryParams;
import com.lms.common.pure.utils.ReflectUtil;
import com.lms.common.web.exception.CheckEntityException;
import com.lms.common.web.service.IBaseService;
import com.lms.common.web.utils.CheckEntityResult;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.Serializable;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends IBaseEntity> extends ServiceImpl<M, T> implements IBaseService<T> {

    @Autowired
    BeanUtilsBean beanUtilsBean;

    @Override
    public IPage<?> query(QueryParams<Map<String, Object>> queryParams) {
        // 获取查询参数
        Map<String, Object> p = queryParams.getFilter();
        int pageIndex = queryParams.getPageIndex();
        int pageSize = queryParams.getPageSize();
        Page<T> page = new Page<>();
        page.setCurrent(pageIndex);
        page.setSize(pageSize);
        return this.queryMapper(page, p);
    }

    @SneakyThrows
    @Override
    @Transactional
    public T saveEntity(Map<String, Object> entity) {
        // 获取实体类类型
//        Class<T> entityType = getEntityType();
        Class<T> entityType = (Class<T>) ReflectUtil.getEntityType(this.getClass(), 1);
        if (entityType == null) throw new NullPointerException("获取实体类类型异常！");
        T instance = entityType.getDeclaredConstructor().newInstance();
        beanUtilsBean.populate(instance, entity);
        saveEntity(instance);
        return instance;
    }

    @Override
    @Transactional
    public void saveEntity(T entity) {
        Serializable id = entity.getKey();
        CheckEntityResult checkRes = null;
        if (id != null) {
            checkRes = this.beforeUpdate(entity, id);
        } else {
            checkRes = this.beforeInsert(entity);
        }
        if (checkRes == null || checkRes.isOk()) {
            this.saveOrUpdate(entity);
            if (id != null) {
                this.afterUpdate(entity);
            } else {
                this.afterInsert(entity);
            }
        } else {
            // 抛出异常
            throw new CheckEntityException(checkRes);
        }
    }

//    private Class<T> getEntityType() {
//        Type type = this.getClass().getGenericSuperclass();
//        if (type instanceof ParameterizedType parameterizedType) {
//            return (Class<T>) parameterizedType.getActualTypeArguments()[1];
//        }
//        throw new RuntimeException();
//    }

    @Override
    public Object get(Serializable id) {
        // 先根据id获取
        T t = this.getById(id);
        return getOneCommon(t);
    }

    @Override
    public Object getByFilter(Map<String, Object> queryParams) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        queryParams.forEach(queryWrapper::eq);
        T t = this.getOne(queryWrapper);
        return getOneCommon(t);
    }

    @Override
    public void delete(Serializable id) {
        // 进行删除前校验
        if (this.beforeDelete(id)) {
            this.removeById(id);
            this.afterDelete(id);
        }
    }

    @Override
    @Transactional
    public void deleteBatch(List<Serializable> ids) {
        List<Serializable> realIds = new ArrayList<>();
        ids.forEach(id -> {
            if (this.beforeDelete(id)) {
                if (id instanceof Integer) {
                    Long _id = Long.valueOf(id.toString());
                    realIds.add(_id);
                } else {
                    realIds.add(id);
                }
            }
        });
        if (!realIds.isEmpty()) {
            this.removeBatchByIds(realIds);
        }
        realIds.forEach(this::afterDelete);
    }

    @SneakyThrows
    @Override
    public void exportExcel(QueryParams<Map<String, Object>> queryParams, HttpServletResponse response) {
        IPage<?> res = this.query(queryParams);
        List<?> records = res.getRecords();
        if (records.isEmpty()) {
            throw new NullPointerException("导出的excel数据不能为空！");
        }
        // 获取导出类类型
        Class<?> clazz = records.get(0).getClass();
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("UTF-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyExcel没有关系
        String encode = URLEncoder.encode("导出数据", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encode + ".xlsx");
        try {
            EasyExcel.write(response.getOutputStream(), clazz)
                    //设置不自动关闭流
                    .autoCloseStream(Boolean.FALSE)
                    .sheet("导出数据")
                    .doWrite(records);
        } catch (IOException e) {
            //重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            com.lms.common.pure.http.HttpResponse<Void> error = com.lms.common.pure.http.HttpResponse.error("下载文件失败！");
            response.getWriter().println(error);
        }
    }

    private Object getOneCommon(T t) {
        // 进行扩展处理
        Object res = this.extensionOne(t);
        if (res == null) {
            return t;
        }
        return res;
    }

}
